home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / RTF / image.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  26KB  |  1,015 lines

  1. #ifndef __lint
  2. static char rcsid[] = "$Id: image.c,v 1.1 92/11/23 12:58:54 pcd Exp Locker: pcd $";
  3. #endif
  4.  
  5. /*
  6.  * image.c
  7.  *
  8.  * convert a hex-encoded sunraster/RLE string into a Pixmap
  9.  * should handle pseudocolor/staticcolor to 16 bits
  10.  * should handle truecolor/directcolor to 32 bits
  11.  *
  12.  * Wade Smith Wed Nov 20 20:04:48 CST 1991
  13.  *
  14.  */
  15.  
  16. /*
  17.  * $Log:    image.c,v $
  18.  * Revision 1.1  92/11/23  12:58:54  pcd
  19.  * Initial checkin
  20.  * 
  21.  * Revision 1.3  92/06/12  16:03:58  connolly
  22.  * *** empty log message ***
  23.  * 
  24.  * Revision 1.5  92/01/03  13:59:44  wsmith
  25.  *     added a check for non-null property buffer before freeing it
  26.  * 
  27.  * Revision 1.4  91/12/18  13:35:36  wsmith
  28.  *     fixed dependence on /usr/avs - notes avs3 # 460
  29.  *     corrected some portability issues - bigendian vs. littleendian
  30.  * 
  31.  * Revision 1.9  91/12/16  16:19:49  wsmith
  32.  * fixed depended on /usr/avs installation directory
  33.  * 
  34.  * Revision 1.8  91/12/16  08:59:53  wsmith
  35.  * support for big-endian and little-endian clients
  36.  * removed check of XPutImage return value
  37.  * 
  38.  * Revision 1.7  91/11/25  13:16:51  wsmith
  39.  * added support for 1-bit sunraster/RLE images
  40.  * 
  41.  * Revision 1.6  91/11/21  12:21:09  wsmith
  42.  * ifdef'd some code used mainly for debugging - several XQueryColor() calls
  43.  * 
  44.  * Revision 1.5  91/11/21  11:15:04  wsmith
  45.  * fixed several lint complaints
  46.  * 
  47.  * Revision 1.4  91/11/21  09:58:15  wsmith
  48.  * added rcs id and log entries
  49.  * 
  50.  */
  51.  
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include <ctype.h>
  56. #include <math.h>
  57. #include <sys/param.h>
  58.  
  59. #include <X11/X.h>
  60. #include <X11/Xlib.h>
  61. #include <X11/Xutil.h>
  62. #include <X11/Xatom.h>
  63.  
  64. #include "rasterfile.h"
  65.  
  66. #define    MAXRGB    8
  67. #define    MAXGREY    256
  68. #define    MAXCOLS    (MAXRGB*MAXRGB*MAXRGB+MAXGREY)
  69. #define    DEFRGB    6
  70. #define    DEFGREY    26
  71. #define    MINRGB    4
  72.  
  73. #define    MAXCOLORS    256
  74. #define    RCOL        0
  75. #define    GCOL        1
  76. #define    BCOL        2
  77.  
  78. #define    MAXSIZE        8192
  79.  
  80. #define    DEF_AVS_PATH    "/usr/avs"
  81. #define    RC_FILE        ".avsrc"
  82. #define    SYS_RC_FILE    "runtime/avsrc"
  83.  
  84. static char *endian = "\377\0";
  85. #define    IS_BIG_ENDIAN    (*(short*)endian<0)
  86. #define    IS_LITTLE_ENDIAN    (*(short*)endian>0)
  87.  
  88. typedef struct raster {
  89.     int        width, height;
  90.     int        ncolors;
  91.     unsigned char    map[MAXCOLORS][3]; 
  92.     unsigned char    *image;
  93. } Raster;
  94.  
  95. typedef struct avsinfo {
  96.     Colormap    colormap;
  97.     int        numred, numgreen, numblue;
  98.     int        numgrey;
  99.     unsigned short    rgbmap[MAXRGB][MAXRGB][MAXRGB];
  100.     unsigned short    greymap[MAXGREY];
  101.     unsigned char    avsmap[MAXCOLS][3];
  102. } AvsInfo;
  103.  
  104. typedef struct rasterfile    RF;
  105.  
  106. static AvsInfo    *saveinfo;
  107. static GC    gc;
  108.  
  109. static float    Gamma;
  110.  
  111. static int    NumRed = -1,
  112.         NumGreen = -1,
  113.         NumBlue = -1,
  114.         NumGrey = -1;
  115.  
  116. static unsigned char    tohex[256] = {
  117. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  118. 0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,
  119. 15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,
  120. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  121. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  122. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  123. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  124. 0,0,0,0,0,0,0,0,0,
  125. };
  126.  
  127. extern char    *getenv();
  128.  
  129. /* count trailing zero bits */
  130. static int
  131. count_zeros(unsigned long i)
  132. {
  133.     int    n = 0;
  134.  
  135.     if (i)
  136.         for (; !(i&1); n++)
  137.         i >>= 1;
  138.     return n;
  139. }
  140.  
  141. /* count one bits in bit mask */
  142. static int 
  143. count_ones(unsigned long i)
  144. {
  145.     int    n;
  146.  
  147.     for (n = 0; i; i >>= 1)
  148.         if (i&1)
  149.             n++;
  150.     return n;
  151. }
  152.  
  153. /* shift left on positive count, right on negative */
  154. static unsigned long
  155. ishift(unsigned long i, int count)
  156. {
  157.     return count >= 0 ? (i<<count) : (i>>(-count));
  158. }
  159.  
  160. /* reverse the bytes in a *(int *) */
  161. static void
  162. reverse_int(int *integer)
  163. {
  164.     char    *p = (char *)integer, tmp;
  165.     int    i, j;
  166.  
  167.     for (i = 0, j = sizeof(int)-1; i < j; i++, j--) {
  168.         tmp = p[i];
  169.         p[i] = p[j];
  170.         p[j] = tmp;
  171.     }
  172. }
  173.  
  174. /* generate colormap value from an index over a range */
  175. static int 
  176. MapCorrect(int i, int max)
  177. {
  178.     if (i <= 0) return 0;
  179.     if (i >= max-1) return 255;
  180.     return (i*255)/(max-1);
  181. }
  182.  
  183. /* open AVS avsrc file */
  184. static FILE *
  185. RCopen()
  186. {
  187.     char    *avs_path;
  188.     char    *class, *home;
  189.     char    path[MAXPATHLEN];
  190.     FILE    *stream;
  191.  
  192.     class = getenv("DISPLAYCLASS");
  193.  
  194.     if (class) {
  195.         (void) sprintf(path, "%s.%s", RC_FILE, class);
  196.         if ((stream = fopen(path, "r")) != NULL)
  197.             return stream;
  198.     }
  199.     if ( (stream = fopen(RC_FILE, "r")) != NULL )
  200.         return stream;
  201.     
  202.     home = getenv("HOME");
  203.     if (home) {
  204.         if (class) {
  205.             (void) sprintf(path, "%s/%s.%s", home, RC_FILE, class);
  206.             if ( (stream = fopen(path, "r")) != NULL )
  207.                 return stream;
  208.         }
  209.         (void) sprintf(path, "%s/%s", home, RC_FILE);
  210.         if ( (stream = fopen(path, "r")) != NULL )
  211.             return stream;
  212.     }
  213.  
  214.     avs_path = getenv("AVS_PATH");
  215.     if (!avs_path) avs_path = DEF_AVS_PATH;
  216.  
  217.     if (class) {
  218.         (void) sprintf(path, "%s/%s.%s", avs_path, SYS_RC_FILE, class);
  219.         if ( (stream = fopen(path, "r")) != NULL )
  220.             return stream;
  221.     }
  222.  
  223.     (void) sprintf(path, "%s/%s", avs_path, SYS_RC_FILE);
  224.     return fopen(path, "r");
  225. }
  226.  
  227. /* get value from avsrc file given property string */
  228. static char *
  229. RCget(const char* string)
  230. {
  231.     static char    line[BUFSIZ];
  232.     FILE        *stream;
  233.  
  234.     stream = RCopen();
  235.     if (stream == NULL) return NULL;
  236.  
  237.     while (fgets(line, BUFSIZ, stream) != NULL) {
  238.         char    *tok, *end;
  239.         int    len, ch;
  240.  
  241.         len = strlen(line);
  242.         if (line[len-1] != '\n') {
  243.             while ( (ch = getc(stream)) != '\n' )
  244.                 if (ch == EOF) {
  245.                     (void) fclose(stream);
  246.                     return NULL;
  247.                 }
  248.             continue;
  249.         } else
  250.             line[len-1] = '\0';
  251.         if (line[0] == '#')
  252.             continue;
  253.         tok = line;
  254.         while (*tok == ' ' || *tok == '\t') tok++;
  255.         for (end = tok; *end && *end != ' ' && *end != '\t'; end++) ;
  256.         if (*end) *end++ = '\0';
  257.         if (!strcmp(tok, string)) {
  258.             (void) fclose(stream);
  259.             return end;
  260.         }
  261.     }
  262.  
  263.     (void) fclose(stream);
  264.     return NULL;
  265. }
  266.  
  267. /* convert hex string to integer */
  268. static int
  269. GetHexadecimal(char* str, int* hex)
  270. {
  271.     char    *tok, *endptr;
  272.  
  273.     if ((tok = strtok(str, " ")) == NULL) return -1;
  274.     *hex = (int) strtol(tok, &endptr, 16);
  275.     return *endptr ? -1 : 0;
  276. }
  277.  
  278. /* handle truecolor and directcolor colormap needs */
  279. static AvsInfo *
  280. TrueAvsInfo(Display* display, int screen, Visual* visual)
  281. {
  282.     int    i;
  283.     int    r,g,b;
  284.     int    red_bits, green_bits, blue_bits;
  285.     int    red_shift, green_shift, blue_shift;
  286.     AvsInfo    *avsinfo;
  287.  
  288.     avsinfo = (AvsInfo *) malloc( sizeof(AvsInfo) );
  289.     if (avsinfo == NULL) return NULL;
  290.  
  291.     red_shift = count_zeros(visual->red_mask);
  292.     green_shift = count_zeros(visual->green_mask);
  293.     blue_shift = count_zeros(visual->blue_mask);
  294.  
  295.     red_bits = count_ones(visual->red_mask);
  296.     green_bits = count_ones(visual->green_mask);
  297.     blue_bits = count_ones(visual->blue_mask);
  298.  
  299.     if (visual->class == DirectColor) {
  300.         int map_size = count_zeros(visual->map_entries);
  301.  
  302.         avsinfo->colormap = XCreateColormap(display, 
  303.             DefaultRootWindow(display), visual, AllocAll);
  304.         for (i = visual->map_entries-1; i >= 0; i--) {
  305.             XColor color;
  306.             r = ishift(i, red_shift+red_bits-map_size);
  307.             g = ishift(i, green_shift+green_bits-map_size);
  308.             b = ishift(i, blue_shift+blue_bits-map_size);
  309.             color.pixel = (r & visual->red_mask) |
  310.                       (g & visual->green_mask) |
  311.                       (b & visual->blue_mask) ;
  312.             color.red = MapCorrect(i, 1<<red_bits)<<8;
  313.             color.green = MapCorrect(i, 1<<green_bits)<<8;
  314.             color.blue = MapCorrect(i, 1<<blue_bits)<<8;
  315.             color.flags = DoRed | DoGreen | DoBlue;
  316.             XStoreColor(display, avsinfo->colormap, &color);
  317.         }
  318.     } else
  319.         avsinfo->colormap = DefaultColormap(display, screen);
  320.     
  321.     return avsinfo;
  322. }
  323.  
  324. #ifdef DEBUG
  325. /* lookup actual colors allocated from colormap */
  326. static void
  327. GetAvsColormap(Display* display, AvsInfo* avsinfo)
  328. {
  329.     int    i;
  330.     int    r,g,b;
  331.     XColor    color;
  332.  
  333.     for (r = 0; r < avsinfo->numred; r++)
  334.         for (g = 0; g < avsinfo->numgreen; g++)
  335.             for (b = 0; b < avsinfo->numblue; b++) {
  336.                 i = avsinfo->rgbmap[r][g][b];
  337.                 color.pixel = i;
  338.                 XQueryColor(display, avsinfo->colormap, &color);
  339.                 avsinfo->avsmap[i][RCOL] = color.red>>8;
  340.                 avsinfo->avsmap[i][GCOL] = color.green>>8;
  341.                 avsinfo->avsmap[i][BCOL] = color.blue>>8;
  342.             }
  343.     
  344.     for (g = 0; g < avsinfo->numgrey; g++) {
  345.         i = avsinfo->greymap[g];
  346.         color.pixel = i;
  347.         XQueryColor(display, avsinfo->colormap, &color);
  348.         avsinfo->avsmap[i][RCOL] = color.red>>8;
  349.         avsinfo->avsmap[i][GCOL] = color.green>>8;
  350.         avsinfo->avsmap[i][BCOL] = color.blue>>8;
  351.     }
  352. }
  353. #endif /*DEBUG*/
  354.  
  355. /* get colormap info from AVS as property on root window */
  356. static AvsInfo *
  357. GetAvsInfo(Display* display, int screen, Visual* visual)
  358. {
  359.     char    value[MAXSIZE];
  360.     unsigned char    *prop;
  361.     int    actual_format;
  362.     int    i,r,g,b;
  363.     int    ncolors;
  364.     long    char_offset;
  365.     unsigned long    nitems, bytes_after;
  366.     Atom    property, actual_type;
  367.     AvsInfo    avsinfo, *new;
  368.     Window    root;
  369.  
  370.     if (visual->class == TrueColor || visual->class == DirectColor)
  371.         return TrueAvsInfo(display, screen, visual);
  372.  
  373.     if (visual->class != PseudoColor)
  374.         return NULL;
  375.  
  376.     property = XInternAtom(display, "AVS_PSEUDO_COLORMAP", False);
  377.     root = DefaultRootWindow(display);
  378.  
  379.     char_offset = 0L;
  380.     while (XGetWindowProperty(display, root, property, 
  381.                   char_offset/sizeof(long),
  382.                   (MAXSIZE-char_offset)/sizeof(long), False, 
  383.                   XA_STRING, &actual_type, &actual_format,
  384.                   &nitems, &bytes_after, &prop) == Success) {
  385.         if (actual_type != XA_STRING || prop == NULL ||
  386.             actual_format != 8 || char_offset+nitems >= MAXSIZE) {
  387.             if (prop) XFree( (char *)prop );
  388.             return NULL;
  389.         }
  390.         memcpy(value+char_offset, (char *)prop, nitems);
  391.         char_offset += nitems;
  392.         XFree( (char *)prop );
  393.         if (bytes_after <= 0)
  394.             break;
  395.     }
  396.  
  397.     if (char_offset <= 0L)
  398.         return NULL;
  399.     value[char_offset] = '\0';
  400.  
  401.     if (GetHexadecimal(value, (int *)&avsinfo.colormap) == -1) return NULL;
  402.     if (GetHexadecimal(NULL, &avsinfo.numred) == -1) return NULL;
  403.     if (GetHexadecimal(NULL, &avsinfo.numgreen) == -1) return NULL;
  404.     if (GetHexadecimal(NULL, &avsinfo.numblue) == -1) return NULL;
  405.     if (GetHexadecimal(NULL, &avsinfo.numgrey) == -1) return NULL;
  406.  
  407.     if (avsinfo.numred < 0 || MAXRGB < avsinfo.numred ||
  408.         avsinfo.numgreen < 0 || MAXRGB < avsinfo.numgreen ||
  409.         avsinfo.numblue < 0 || MAXRGB < avsinfo.numblue ||
  410.         avsinfo.numgrey < 0 || MAXGREY < avsinfo.numgrey)
  411.         return NULL;
  412.  
  413.     ncolors = (avsinfo.numred*avsinfo.numgreen*avsinfo.numblue)+
  414.           avsinfo.numgrey;
  415.     if (ncolors > MAXCOLS)
  416.         return NULL;
  417.     
  418.     for (r = 0; r < avsinfo.numred; r++)
  419.         for (g = 0; g < avsinfo.numgreen; g++)
  420.             for (b = 0; b < avsinfo.numblue; b++) {
  421.                 if (GetHexadecimal(NULL, &i) == -1) return NULL;
  422.                 if (i < 0 || MAXCOLS < i) return NULL;
  423.                 avsinfo.rgbmap[r][g][b] = i;
  424.             }
  425.     
  426.     for (g = 0; g < avsinfo.numgrey; g++) {
  427.         if (GetHexadecimal(NULL, &i) == -1) return NULL;
  428.         if (i < 0 || MAXCOLS < i) return NULL;
  429.         avsinfo.greymap[g] = i;
  430.     }
  431.  
  432. #ifdef DEBUG
  433.     GetAvsColormap(display, &avsinfo);
  434. #endif /*DEBUG*/
  435.  
  436.     new = (AvsInfo *) malloc( sizeof(avsinfo) );
  437.     if (new == NULL) return NULL;
  438.  
  439.     (void) memcpy((char *)new,(char *)&avsinfo,sizeof(avsinfo));
  440.     return new;
  441. }
  442.  
  443. /* gamma correct an integer over a range */
  444. static int
  445. GammaCorrect(int i, int num)
  446. {
  447.     float    f;
  448.  
  449.     if (i <= 0) return 0;
  450.     if (i >= num-1) return 255;
  451.     f = (float) i / (float) (num-1);
  452.     return (int) (pow(f, 1/Gamma) * 255);
  453. }
  454.  
  455. /* allocate a single color from colormap */
  456. static long
  457. AllocColor(Display* display, Colormap colormap, int r, int g, int b)
  458. {
  459.     XColor    cell;
  460.     
  461.     cell.red   = (r & 0xff) << 8;
  462.     cell.green = (g & 0xff) << 8;
  463.     cell.blue  = (b & 0xff) << 8;
  464.     cell.flags = DoRed | DoGreen | DoBlue;
  465.  
  466.     if (!XAllocColor(display, colormap, &cell))
  467.         return -1;
  468.     
  469.     return cell.pixel;
  470. }
  471.  
  472. /* try to allocate colors in AVS fashion from colormap */
  473. static int
  474. AllocColors(Display* display, AvsInfo* avsinfo)
  475. {
  476.     int    i;
  477.     int    r,g,b;
  478.     long    pixel;
  479.     unsigned long pixels[MAXCOLS];
  480.  
  481.     i = 0;
  482.     for (r = 0; r < avsinfo->numred; r++)
  483.         for (g = 0; g < avsinfo->numgreen; g++)
  484.             for (b = 0; b < avsinfo->numblue; b++) {
  485.                 pixel = AllocColor( display, avsinfo->colormap,
  486.                         GammaCorrect(r, avsinfo->numred),
  487.                         GammaCorrect(g, avsinfo->numgreen),
  488.                         GammaCorrect(b, avsinfo->numblue)
  489.                     );
  490.                 if (pixel == -1) {
  491.                     XFreeColors(display, avsinfo->colormap,
  492.                             pixels, i, 0);
  493.                     return 0;
  494.                 }
  495.                 pixels[i++] = avsinfo->rgbmap[r][g][b] = pixel;
  496.             }
  497.     
  498.     for (g = 0; g < avsinfo->numgrey; g++) {
  499.         pixel = AllocColor( display, avsinfo->colormap,
  500.                     GammaCorrect(g, avsinfo->numgrey),
  501.                     GammaCorrect(g, avsinfo->numgrey),
  502.                     GammaCorrect(g, avsinfo->numgrey)
  503.             );
  504.         if (pixel == -1) {
  505.             XFreeColors(display, avsinfo->colormap, pixels, i, 0);
  506.             return 0;
  507.         }
  508.         pixels[i++] = avsinfo->greymap[g] = pixel;
  509.     }
  510.  
  511.     return 1;
  512. }
  513.  
  514. /* allocate pseudocolor colormap by reducing color needs */
  515. static int 
  516. AllocAvsColormap(Display* display, int screen, Visual* visual, AvsInfo* avsinfo)
  517. {
  518.     if (DefaultDepth(display, screen) > 8 && 
  519.         visual->map_entries >= MAXCOLS) {
  520.         avsinfo->numred = MAXRGB;
  521.         avsinfo->numgreen = MAXRGB;
  522.         avsinfo->numblue = MAXRGB;
  523.         avsinfo->numgrey = MAXGREY;
  524.     } else if (NumRed != -1) {
  525.         avsinfo->numred = NumRed;
  526.         avsinfo->numgreen = NumGreen;
  527.         avsinfo->numblue = NumBlue;
  528.         avsinfo->numgrey = NumGrey;
  529.     } else {
  530.         avsinfo->numred = DEFRGB;
  531.         avsinfo->numgreen = DEFRGB;
  532.         avsinfo->numblue = DEFRGB;
  533.         avsinfo->numgrey = DEFGREY;
  534.     }
  535.  
  536.     for (;;) {
  537.         if (AllocColors(display, avsinfo))
  538.             break;
  539.         avsinfo->numred--;
  540.         avsinfo->numgreen--;
  541.         avsinfo->numblue--;
  542.         avsinfo->numgrey = (avsinfo->numred-1)*(avsinfo->numred-1)+1;
  543.         if (avsinfo->numred < MINRGB)
  544.             return 0;
  545.     }
  546.     
  547.     return 1;
  548. }
  549.  
  550. /* create our own colormap rather than using AVS's colormap */
  551. static AvsInfo *
  552. CreateAvsInfo(Display* display, int screen, Visual* visual)
  553. {
  554.     AvsInfo    avsinfo, *new;
  555.  
  556.     if (visual->class == TrueColor || visual->class == DirectColor)
  557.         return TrueAvsInfo(display, screen, visual);
  558.  
  559.     avsinfo.colormap = DefaultColormap(display, screen);
  560.     if (!AllocAvsColormap(display, screen, visual, &avsinfo)) {
  561.         avsinfo.colormap = XCreateColormap(display, 
  562.             DefaultRootWindow(display), visual, AllocNone);
  563.         if (!AllocAvsColormap(display, screen, visual, &avsinfo))
  564.             return NULL;
  565.     }
  566.  
  567. #ifdef DEBUG
  568.     GetAvsColormap(display, &avsinfo);
  569. #endif /*DEBUG*/
  570.  
  571.     new = (AvsInfo *) malloc( sizeof(avsinfo) );
  572.     if (new == NULL) return NULL;
  573.  
  574.     (void) memcpy((char *)new,(char *)&avsinfo,sizeof(avsinfo));
  575.     return new;
  576. }
  577.  
  578. /* initialize state data, select colormap and allocate colors */
  579. static AvsInfo *
  580. InitDisplayInfo(Display* display, int screen, Visual* visual, int child_of_avs)
  581. {
  582.     char    *avs_gamma, *avs_colors;
  583.  
  584.     avs_gamma = RCget("Gamma");
  585.     if (getenv("AVS_GAMMA")) avs_gamma = getenv("AVS_GAMMA");
  586.     if (avs_gamma) {
  587.         Gamma = atof(avs_gamma);
  588.         if (Gamma <= 0.0) Gamma = 3, Gamma/=2; /* no fp constants */
  589.     }
  590.  
  591.     avs_colors = RCget("Colors");
  592.     if (getenv("AVS_COLORS")) avs_colors = getenv("AVS_COLORS");
  593.     if (avs_colors) {
  594.         if (sscanf(avs_colors, " %d %d %d %d", 
  595.             &NumRed, &NumGreen, &NumBlue, &NumGrey) != 4 ||
  596.                    NumRed <= 0 || MAXRGB < NumRed ||
  597.                NumGreen <= 0 || MAXRGB < NumGreen ||
  598.                NumBlue <= 0 || MAXRGB < NumBlue ||
  599.                NumGrey <= 0 || MAXGREY < NumGrey)
  600.             NumRed = NumGreen = NumBlue = NumGrey = -1;
  601.     }
  602.  
  603.     return child_of_avs ? GetAvsInfo(display, screen, visual) :
  604.                  CreateAvsInfo(display, screen, visual) ;
  605. }
  606.  
  607. /* return the next decoded byte from a hex string */
  608. static int
  609. getbyte(const char* string)
  610. {
  611.     static unsigned char*    ptr;
  612.     int            i, byte;
  613.  
  614.     if (string) {
  615.         ptr = (unsigned char *)string;
  616.         return EOF;
  617.     }
  618.     
  619.     byte = 0;
  620.     for (i = 0; i < 2; ptr++)
  621.         if (isxdigit(*ptr))
  622.             byte = (byte<<4)|tohex[*ptr], i++;
  623.         else if (*ptr != '\n') 
  624.             return EOF;
  625.  
  626.     return byte;
  627. }
  628.  
  629. /* return a block of characters from a hex string */
  630. static int
  631. bread(char* buf, int nbytes)
  632. {
  633.     int    i, byte;
  634.  
  635.     for (i = 0; i < nbytes; i++) {
  636.         if ((byte = getbyte(NULL)) == EOF)
  637.             return i ? i : EOF;
  638.         *buf++ = byte;
  639.     }
  640.     return i;
  641. }
  642.  
  643. /* change byte order for little-endian machines */
  644. static void
  645. ReverseRasterfileHeader(RF *rf)
  646. {
  647.     reverse_int( &rf->ras_magic );
  648.     reverse_int( &rf->ras_width );
  649.     reverse_int( &rf->ras_height );
  650.     reverse_int( &rf->ras_depth );
  651.     reverse_int( &rf->ras_length );
  652.     reverse_int( &rf->ras_type );
  653.     reverse_int( &rf->ras_maptype );
  654.     reverse_int( &rf->ras_maplength );
  655. }
  656.  
  657. /* return width and height info from rasterfile header in hex string */
  658. static int
  659. GetHeaderFromString(const char* string, int* width, int* height)
  660. {
  661.     RF    rf;
  662.     
  663.     (void) getbyte(string);
  664.  
  665.     if (bread((char *)&rf, sizeof(rf)) != sizeof(rf)) return 0;
  666.     if (IS_LITTLE_ENDIAN) ReverseRasterfileHeader(&rf);
  667.     if (rf.ras_magic != RAS_MAGIC) return 0;
  668.  
  669.     *width = rf.ras_width;
  670.     *height = rf.ras_height;
  671.     return *width > 0 && *height > 0;
  672. }
  673.  
  674. /* extract raster info from hex string */
  675. static Raster *
  676. GetRasterFromString(const char* string)
  677. {
  678.     unsigned char    *src, *dst, *end, *data;
  679.     int    ch, size, bytes_per_line, depth;
  680.     int    i, x, y, bit;
  681.     RF    rf;
  682.     Raster    raster, *new;
  683.  
  684.     (void) getbyte(string);
  685.  
  686.     if (bread((char *)&rf, sizeof(rf)) != sizeof(rf)) return NULL;
  687.     if (IS_LITTLE_ENDIAN) ReverseRasterfileHeader(&rf);
  688.     if (rf.ras_magic != RAS_MAGIC) return NULL;
  689.     if (rf.ras_depth != 1 && rf.ras_depth != 8) return NULL;
  690.     if (rf.ras_type != RT_BYTE_ENCODED) return NULL;
  691.  
  692.     raster.width = rf.ras_width;
  693.     raster.height = rf.ras_height;
  694.     if (raster.width <= 0 || raster.height <= 0) return NULL;
  695.     depth = rf.ras_depth;
  696.  
  697.     if (rf.ras_maptype == RMT_EQUAL_RGB) {
  698.         raster.ncolors = rf.ras_maplength/3;
  699.         if (raster.ncolors <= 0 || raster.ncolors > (1<<depth)) 
  700.             return NULL;
  701.  
  702.         for (i = 0; i < raster.ncolors; i++) {
  703.             ch = getbyte(NULL);
  704.             if (ch == EOF) return NULL;
  705.             raster.map[i][RCOL] = ch;
  706.         }
  707.  
  708.         for (i = 0; i < raster.ncolors; i++) {
  709.             ch = getbyte(NULL);
  710.             if (ch == EOF) return NULL;
  711.             raster.map[i][GCOL] = ch;
  712.         }
  713.  
  714.         for (i = 0; i < raster.ncolors; i++) {
  715.             ch = getbyte(NULL);
  716.             if (ch == EOF) return NULL;
  717.             raster.map[i][BCOL] = ch;
  718.         }
  719.     } else if (depth == 1 && rf.ras_maptype == RMT_NONE) {
  720.         raster.ncolors = 2;
  721.         raster.map[0][RCOL] = 255;    /* slot 0 - white */
  722.         raster.map[0][GCOL] = 255;
  723.         raster.map[0][BCOL] = 255;
  724.         raster.map[1][RCOL] = 0;    /* slot 1 - black */
  725.         raster.map[1][GCOL] = 0;
  726.         raster.map[1][BCOL] = 0;
  727.     } else
  728.         return NULL;
  729.  
  730.     bytes_per_line = ((raster.width*depth + 15)/16)*2;
  731.     size = bytes_per_line * raster.height;
  732.     raster.image = (unsigned char *)malloc( size );
  733.     if (raster.image == NULL) return NULL;
  734.  
  735.     dst = raster.image;
  736.     end = raster.image+size;
  737.     while (dst < end) {
  738.         ch = getbyte(NULL);
  739.         if (ch == EOF) { free(raster.image); return NULL; }
  740.         if (ch == 0x80) {
  741.             int n = getbyte(NULL);
  742.             if (n == EOF) { free(raster.image); return NULL; }
  743.             if (n > 0) {
  744.                 ch = getbyte(NULL);
  745.                 if (ch == EOF) 
  746.                     { free(raster.image); return NULL; }
  747.                 while (dst < end && n-- > -1) 
  748.                     *dst++ = ch;
  749.             } else
  750.                 *dst++ = ch;
  751.         } else
  752.             *dst++ = ch;
  753.     }
  754.  
  755.     if (depth == 1) {
  756.         data = (unsigned char *)malloc( raster.width*raster.height );
  757.         if (data == NULL) { free(raster.image); return NULL; }
  758.         /* assume big-endian bit order */
  759.         for (y = 0; y < raster.height; y++) {
  760.             src = raster.image+y*bytes_per_line;
  761.             dst = data+y*raster.width;
  762.             bit = 7;
  763.             for (x = 0; x < raster.width; x++) {
  764.             *dst++ = (*src>>bit)&1;
  765.             if (--bit < 0) { src++; bit = 7; }
  766.             }
  767.         }
  768.         free( raster.image );
  769.         raster.image = data;
  770.     } else if (raster.width != bytes_per_line) {
  771.         data = (unsigned char *)malloc(raster.width*raster.height);
  772.         if (data == NULL) { free( raster.image ); return NULL; }
  773.         for (y = 0; y < raster.height; y++)
  774.             memcpy(data+y*raster.width, 
  775.                    raster.image+y*bytes_per_line, raster.width);
  776.         free( raster.image );
  777.         raster.image = data;
  778.     }
  779.  
  780.     new = (Raster *)malloc( sizeof(raster) );
  781.     if (new == NULL) return NULL;
  782.  
  783.     (void) memcpy( (void *)new, (void *)&raster, sizeof(raster) );
  784.     return new;
  785. }
  786.  
  787. /* convert raster image to pseudocolor/staticcolor format */
  788. static XImage *
  789. pseudo_image(Display* display, 
  790.     Visual* visual, int depth, Raster* raster, AvsInfo* avsinfo)
  791. {
  792.     char    *data;
  793.     int    i, size, bits_per_pixel;
  794.     int    r, g, b;
  795.     unsigned short    map[MAXCOLORS];
  796.     XImage    *image;
  797.  
  798.     for (i = 0; i < raster->ncolors; i++) {
  799.         r = raster->map[i][RCOL];
  800.         g = raster->map[i][GCOL];
  801.         b = raster->map[i][BCOL];
  802.         if (r == g && g == b) {
  803.             g = (g * avsinfo->numgrey) / 256;
  804.             map[i] = avsinfo->greymap[g];
  805.         } else {
  806.             r = (r * avsinfo->numred) / 256;
  807.             g = (g * avsinfo->numgreen) / 256;
  808.             b = (b * avsinfo->numblue) / 256;
  809.             map[i] = avsinfo->rgbmap[r][g][b];
  810.         }
  811.     }
  812.  
  813.     size = raster->width * raster->height;
  814.  
  815.     if (depth > 8) {
  816.         unsigned short    *ptr;
  817.         ptr = (unsigned short *)malloc( size * sizeof(short) );
  818.         if (ptr == NULL) return NULL;
  819.         for (i = 0; i < size; i++)
  820.             ptr[i] = map[ raster->image[i] ];
  821.         data = (char *)ptr;
  822.         bits_per_pixel = 16;
  823.     } else {
  824.         unsigned char    *ptr;
  825.         ptr = (unsigned char *)malloc( size * sizeof(char) );
  826.         if (ptr == NULL) return NULL;
  827.         for (i = 0; i < size; i++)
  828.             ptr[i] = map[ raster->image[i] ];
  829.         data = (char *)ptr;
  830.         bits_per_pixel = 8;
  831.     }
  832.  
  833.     image = XCreateImage(display, visual, depth, ZPixmap, 0, (char *)data, 
  834.                  raster->width, raster->height, bits_per_pixel,
  835.                  raster->width*bits_per_pixel/8);
  836.     if (image == NULL) return NULL;
  837.     
  838.     image->byte_order = (IS_BIG_ENDIAN ? MSBFirst : LSBFirst);
  839.     image->bitmap_unit = bits_per_pixel;
  840.     image->bitmap_bit_order = (IS_BIG_ENDIAN ? MSBFirst : LSBFirst);
  841.  
  842.     image->bits_per_pixel = bits_per_pixel;
  843.     return image;
  844. }
  845.  
  846. /* convert raster image to truecolor/directcolor format */
  847. static XImage *
  848. true_image(Display* display, Visual* visual, int depth, Raster* raster)
  849. {
  850.     char    *data;
  851.     int    i, size;
  852.     int    r,g,b;
  853.     int    red_bits, green_bits, blue_bits;
  854.     int    red_shift, green_shift, blue_shift;
  855.     int    bits_per_pixel;
  856.     long    pixels[MAXCOLORS];
  857.     XImage    *image;
  858.  
  859.     red_shift = count_zeros(visual->red_mask);
  860.     green_shift = count_zeros(visual->green_mask);
  861.     blue_shift = count_zeros(visual->blue_mask);
  862.  
  863.     red_bits = count_ones(visual->red_mask);
  864.     green_bits = count_ones(visual->green_mask);
  865.     blue_bits = count_ones(visual->blue_mask);
  866.  
  867.     for (i = 0; i < raster->ncolors; i++) {
  868.         r = GammaCorrect(raster->map[i][RCOL], MAXCOLORS);
  869.         g = GammaCorrect(raster->map[i][GCOL], MAXCOLORS);
  870.         b = GammaCorrect(raster->map[i][BCOL], MAXCOLORS);
  871.         r = ishift(r, red_shift+red_bits-8);
  872.         g = ishift(g, green_shift+green_bits-8);
  873.         b = ishift(b, blue_shift+blue_bits-8);
  874.         pixels[i] = (r & visual->red_mask) |
  875.                 (g & visual->green_mask) |
  876.                 (b & visual->blue_mask) ;
  877.     }
  878.  
  879.     size = raster->width * raster->height;
  880.  
  881.     if (depth > 16) {
  882.         unsigned long    *ptr;
  883.         ptr = (unsigned long *)malloc( size * sizeof(long) );
  884.         if (ptr == NULL) return NULL;
  885.         for (i = 0; i < size; i++)
  886.             ptr[i] = pixels[ raster->image[i] ];
  887.         data = (char *)ptr;
  888.         bits_per_pixel = sizeof(long)*8;
  889.     } else if (depth > 8) {
  890.         unsigned short    *ptr;
  891.         ptr = (unsigned short *)malloc( size * sizeof(short) );
  892.         if (ptr == NULL) return NULL;
  893.         for (i = 0; i < size; i++)
  894.             ptr[i] = pixels[ raster->image[i] ];
  895.         data = (char *)ptr;
  896.         bits_per_pixel = sizeof(short)*8;
  897.     } else {
  898.         unsigned char    *ptr;
  899.         ptr = (unsigned char *)malloc( size * sizeof(char) );
  900.         if (ptr == NULL) return NULL;
  901.         for (i = 0; i < size; i++)
  902.             ptr[i] = pixels[ raster->image[i] ];
  903.         data = (char *)ptr;
  904.         bits_per_pixel = sizeof(char)*8;
  905.     }
  906.     
  907.     image = XCreateImage(display, visual, depth, ZPixmap, 0, data, 
  908.                  raster->width, raster->height, bits_per_pixel,
  909.                  raster->width*bits_per_pixel/8);
  910.     if (image == NULL) return NULL;
  911.  
  912.     image->byte_order = (IS_BIG_ENDIAN ? MSBFirst : LSBFirst);
  913.     image->bitmap_unit = bits_per_pixel;
  914.     image->bitmap_bit_order = (IS_BIG_ENDIAN ? MSBFirst : LSBFirst);
  915.  
  916.     image->bits_per_pixel = bits_per_pixel;
  917.     image->red_mask = visual->red_mask;
  918.     image->green_mask = visual->green_mask;
  919.     image->blue_mask = visual->blue_mask;
  920.  
  921.     return image;
  922. }
  923.  
  924. /* free Raster* struct */
  925. static void
  926. FreeRaster(Raster* raster)
  927. {
  928.     free( (char *)raster->image );
  929.     free( (char *)raster );
  930. }
  931.  
  932. int
  933. initializeImageBuilder(Display* display)
  934. /* USE: 
  935.  *    if (initializeImageBuilder(disp, child_of_avs, avs_visualid, &cmap)) {
  936.  *        if (cmap)
  937.  *            XtVaSetValues(toplevel, XtNcolormap, cmap);
  938.  *    } else
  939.  *         printf("could not initialize image converter.\n");
  940.  */
  941. {
  942.     int root = DefaultRootWindow(display);
  943.     int screen = DefaultScreen(display);
  944.     Visual* visual = DefaultVisual(display,screen);
  945.  
  946.     Gamma = 3; /* DEFGAMMA with no float constants */
  947.     Gamma /= 2;
  948.  
  949.     gc = XCreateGC(display, root, 0L, (XGCValues *)0);
  950.  
  951.     saveinfo = InitDisplayInfo(display, screen, visual, 0);
  952.     if (saveinfo == NULL) return 0;
  953.  
  954.     return 1;
  955. }
  956.  
  957. int
  958. getImageSize(const char* data, int* width, int* height)
  959. /* USE:
  960.  *    data = "0123456789ABCDEF\nFF00FF00FF00FF00\n...";
  961.  *    if (getImageSize(data, &w, &h)
  962.  *        printf("image size: %dx%d\n", w, h);
  963.  *    else
  964.  *        printf("not a sun raster.\n");
  965.  */
  966. {
  967.     return GetHeaderFromString(data, width, height);
  968. }
  969.  
  970. Pixmap
  971. createPixmapFromHexData(Display* display, Drawable drawable, const char* data)
  972. /* USE:
  973.  *    data = "0123456789ABCDEF\nFF00FF00FF00FF00\n...";
  974.  *    getImageSize(data, &w, &h);
  975.  *    pixmap = createPixmapFromHexData(disp, drawable, data);
  976.  */
  977. {
  978.     int screen = DefaultScreen(display);
  979.     Visual* visual = DefaultVisual(display,screen);
  980.     int depth  = DefaultDepth(display,screen);
  981.     Raster    *raster;
  982.     Pixmap    pixmap;
  983.     XImage    *image;
  984.  
  985.     raster = GetRasterFromString(data);
  986.     if (raster == NULL) return 0;
  987.  
  988.     if (visual->class == PseudoColor || visual->class == StaticColor)
  989.         image = pseudo_image(display, visual, depth, raster, saveinfo);
  990.     else if (visual->class == DirectColor || visual->class == TrueColor)
  991.         image = true_image(display, visual, depth, raster);
  992.     else
  993.         image = NULL;
  994.  
  995.     if (image == NULL) {
  996.         FreeRaster(raster);
  997.         return 0;
  998.     }
  999.  
  1000.     pixmap = XCreatePixmap(display, drawable, 
  1001.                    raster->width, raster->height, depth);
  1002.     if (!pixmap) {
  1003.         FreeRaster(raster);
  1004.         XDestroyImage(image);
  1005.         return 0;
  1006.     }
  1007.  
  1008.     XPutImage(display, pixmap, gc, image, 
  1009.           0, 0, 0, 0, raster->width, raster->height);
  1010.  
  1011.     FreeRaster(raster);
  1012.     XDestroyImage(image);
  1013.     return pixmap;
  1014. }
  1015.